#include "kernelsetup.h"
#include "kernelctl.h"
#include <iostream>
#include <cstring>
#include <bcm/bcm.h>

class CooperativeMode : public conin::base::CooperativeTask
{
protected:
	conin::base::KernelSetup *scheduler_;
	conin::base::OperationModeID mode_;
	const char *item(conin::base::OperationModeID mode)
	{
		static const char *name[] = {
			"Modo de configuracion",
			"Modo IMD",
			"Modo impulso",
			"Modo rapido",
			"Modo manivela",
			"Modo memoria",
			"Modo administrador de archivos",
			"Modo edicion",
			"Salir"
		};
		return name[mode];
	}
	conin::base::OperationModeID menu()
	{
		int option;
		for (int i = conin::base::OPMODE_SETUP; i <= conin::base::OPMODE_END; i++)
			std::cout << "\t" << i << ". " << item(conin::base::OperationModeID(i)) << std::endl;
		std::cin >> option;
		return static_cast<conin::base::OperationModeID>(option);
	}
public:
	CooperativeMode(conin::base::OperationModeID mode, conin::base::KernelSetup *scheduler)
		: mode_(mode), scheduler_(scheduler) {}
	virtual void start()
	{
		std::cout << "Iniciar " << item(mode_) << "." << std::endl;
	}
	virtual bool execute()
	{
		std::cout << item(mode_) << std::endl;
		int len = strlen(item(mode_));
		for (int i = 0; i < len; i++)
			std::cout << '-';
		std::cout << std::endl;
		conin::base::OperationModeID mode = menu();
		if (mode == mode_)
			return true;
		else if (mode != conin::base::OPMODE_END)
			scheduler_->selectMode(mode);
		return false;
	}
	virtual void stop()
	{
		std::cout << "Detener " << item(mode_) << "." << std::endl;
	}
};

class BackgroundTask : public conin::base::CooperativeTask
{
public:
	virtual void start()
	{
		std::cout << "Iniciar tarea de segundo plano." << std::endl;
	}
	virtual bool execute()
	{
		std::cout << "Ejecutar tarea de segundo plano." << std::endl;
		return true;
	}
	virtual void stop()
	{
		std::cout << "Detener tarea de segundo plano." << std::endl;
	}
};

int main()
{
	conin::base::KernelControl *krnlCtl_ = 0;
	bcm::ComponentManager &compMgr = bcm::ComponentManager::instance();
	switch (compMgr.loadComponent(TEXT("cnckernel.dll"))) {
	case bcm::LC_NODLL:
		std::cout << "No se pudo cargar la DLL del nucleo CNC." << std::endl;
		return 1;
	case bcm::LC_NOCOMPONENT:
		std::cout << "No se pudo leer el componente del nucleo CNC." << std::endl;
		return 1;
	case bcm::LC_ALREADYUSED:
		std::cout << "El componente del nucleo CNC ya fue registrado." << std::endl;
		return 1;
	case bcm::LC_OK:
		std::cout << "El componente del nucleo CNC fue cargado correctamente." << std::endl;
		break;
	}
	bcm::Component *component;
	switch (compMgr.getComponent("cnckrnl", &component)) {
	case bcm::GC_UNREGISTERED:
		std::cout << "Componente del nucleo CNC nunca fue registrado." << std::endl;
		return 1;
	case bcm::GC_NOCOMPONENT:
		std::cout << "Componente del nucleo CNC no está disponible." << std::endl;
		return 1;
	case bcm::GC_INCOMPLETE:
		std::cout << "Componente del nucleo CNC cargado incompletamente." << std::endl;
		return 1;
	case bcm::GC_OK:
		std::cout << "El componente del nucleo CNC fue recuperado correctamente." << std::endl;
		break;
	}
	bcm::Interface *iface;
	iface = component->getInterface("krnlsetup");
	if (iface == 0) {
		std::cout << "1. La interfaz configuracion del nucleo CNC no fue recuperada correctamente." << std::endl;
		return 1;
	}
	conin::base::KernelSetup *krnlSetup = dynamic_cast<conin::base::KernelSetup *>(iface);
	if (krnlSetup == 0) {
		std::cout << "2. La interfaz configuracion del nucleo CNC no fue recuperada correctamente." << std::endl;
		return 1;
	}
	BackgroundTask guiTask;
	CooperativeMode setupMode(conin::base::OPMODE_SETUP, krnlSetup);
	CooperativeMode mdiMode(conin::base::OPMODE_MDI, krnlSetup);
	CooperativeMode jogMode(conin::base::OPMODE_JOG, krnlSetup);
	CooperativeMode rapidMode(conin::base::OPMODE_RAPID, krnlSetup);
	CooperativeMode handwheelMode(conin::base::OPMODE_HANDWHEEL, krnlSetup);
	CooperativeMode memoryMode(conin::base::OPMODE_MEMORY, krnlSetup);
	CooperativeMode tapeMode(conin::base::OPMODE_TAPE, krnlSetup);
	CooperativeMode editMode(conin::base::OPMODE_EDIT, krnlSetup);
	krnlSetup->addTask(&guiTask);
	krnlSetup->addMode(conin::base::OPMODE_SETUP, &setupMode);
	krnlSetup->addMode(conin::base::OPMODE_MDI, &mdiMode);
	krnlSetup->addMode(conin::base::OPMODE_JOG, &jogMode);
	krnlSetup->addMode(conin::base::OPMODE_RAPID, &rapidMode);
	krnlSetup->addMode(conin::base::OPMODE_HANDWHEEL, &handwheelMode);
	krnlSetup->addMode(conin::base::OPMODE_MEMORY, &memoryMode);
	krnlSetup->addMode(conin::base::OPMODE_TAPE, &tapeMode);
	krnlSetup->addMode(conin::base::OPMODE_EDIT, &editMode);
	krnlSetup->selectMode(conin::base::OPMODE_SETUP);
	iface = component->getInterface("krnlctl");
	if (iface == 0) {
		std::cout << "1. La interfaz control del nucleo CNC no fue recuperada correctamente." << std::endl;
		return 1;
	}
	krnlCtl_ = dynamic_cast<conin::base::KernelControl *>(iface);
	if (krnlCtl_ == 0) {
		std::cout << "2. La interfaz control del nucleo CNC no fue recuperada correctamente." << std::endl;
		return 1;
	}
	krnlCtl_->start();
	krnlCtl_->execute();
	krnlCtl_->stop();
	return 0;
}

